/**
 * @file uc_spi->c
 * @author PoplarTang (poplar_tang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-15
 *
 * @copyright Copyright (c) 2023
 *
 */
#include "UP_SPI.h"
#include "UP_GPIO.h"
#include "gd32f4xx.h"
#include "systick.h"

void SPI_init(uint32_t spi_periph)
{
    spi_parameter_struct spi_init_struct;
    /* configure SPI4 parameter */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX; // 传输模式全双工
    spi_init_struct.device_mode          = SPI_MASTER;               // 配置为主机
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;       // 8位数据
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;  // 时钟极性高电平，时钟相位第二个边沿
    spi_init_struct.nss                  = SPI_NSS_SOFT;             // 软件cs
    spi_init_struct.prescale             = SPI_PSC_2;                // 2分频
    spi_init_struct.endian               = SPI_ENDIAN_MSB;           // 高位在前

    UP_SPI uc_spi = uc_spi_default;
    uc_spi.spi_init_struct = &spi_init_struct;
    // 这里要根据数据手册中的2.6.5表格进行配置
    uc_spi.pin_sck         = PF7;
    uc_spi.pin_sck.af      = GPIO_AF_5;
    uc_spi.pin_miso        = PF8;
    uc_spi.pin_miso.af     = GPIO_AF_5;
    uc_spi.pin_mosi        = PF9;
    uc_spi.pin_mosi.af     = GPIO_AF_5;

    SPI_init_with_config(spi_periph, &uc_spi);
}

/**
 * \brief          SPI初始化
 * 
 *      默认提供四种典型的连接模式
 *      主机MFD <-> 从机SFD 全双工模式
 *      主机MRU <-  从机STU 单工模式
 *      主机MTU  -> 从机SRU 单工模式
 *      主机MTB/MRB <-> 从机SRB/STB 双向线连接模式
 *
 */
void SPI_init_with_config(uint32_t spi_periph, UP_SPI *uc_spi)
{

    switch (spi_periph) {

        case SPI0:
            rcu_periph_clock_enable(RCU_SPI0); // 使能SPI0
            break;
        case SPI1:
            rcu_periph_clock_enable(RCU_SPI1); // 使能SPI1
            break;
        case SPI2:
            rcu_periph_clock_enable(RCU_SPI2); // 使能SPI2
            break;
        case SPI3:
            rcu_periph_clock_enable(RCU_SPI3); // 使能SPI3
            break;
        case SPI4:
            rcu_periph_clock_enable(RCU_SPI4); // 使能SPI4
            break;
        case SPI5:
            rcu_periph_clock_enable(RCU_SPI5); // 使能SPI5
            break;
        default:
            break;
    }
    // 如果uc_spi->pin_sck不为空，则配置SCK
    if (uc_spi->pin_sck.port != 0) {
        GPIO_Init_AF(uc_spi->pin_sck, uc_spi->pin_sck.af);
        GPIO_Set(uc_spi->pin_sck, 1);
    }
    // 如果uc_spi->pin_miso不为空，则配置MISO
    if (uc_spi->pin_miso.port != 0) {
        GPIO_Init_AF(uc_spi->pin_miso, uc_spi->pin_sck.af);
        GPIO_Set(uc_spi->pin_miso, 1);
    }
    // 如果uc_spi->pin_mosi不为空，则配置MOSI
    if (uc_spi->pin_mosi.port != 0) {
        GPIO_Init_AF(uc_spi->pin_mosi, uc_spi->pin_sck.af);
        GPIO_Set(uc_spi->pin_mosi, 1);
    }
    if (uc_spi->pin_nss.port != 0) {
        GPIO_Init_AF(uc_spi->pin_nss, uc_spi->pin_sck.af);
        GPIO_Set(uc_spi->pin_nss, 1);
    }
    if (uc_spi->pin_io2.port != 0) {
        GPIO_Init_AF(uc_spi->pin_io2, uc_spi->pin_sck.af);
        GPIO_Set(uc_spi->pin_io2, 1);
    }
    if (uc_spi->pin_io3.port != 0) {
        GPIO_Init_AF(uc_spi->pin_io3, uc_spi->pin_sck.af);
        GPIO_Set(uc_spi->pin_io3, 1);
    }

    spi_init(spi_periph, uc_spi->spi_init_struct);

    /* enable SPI */
    spi_enable(spi_periph);
}
uint8_t SPI_read(uint32_t spi_periph)
{
    while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE))
        ;
    return spi_i2s_data_receive(spi_periph);
}

void SPI_write(uint32_t spi_periph, uint8_t dat)
{
    while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE))
        ;
    spi_i2s_data_transmit(spi_periph, dat);
    while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE))
        ;
}